/*  Copyright (c) MediaArea.net SARL. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license that can
 *  be found in the License.html file in the root of the source tree.
 */

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Microsoft Visual C# wrapper for MediaInfo Library
// See MediaInfo.h for help
//
// To make it working, you must put MediaInfo.Dll
// in the executable folder
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


using System;
using System.Runtime.InteropServices;

#pragma warning disable 1591 // Disable XML documentation warnings

namespace MediaInfoLib
{
    public enum StreamKind
    {
        General,
        Video,
        Audio,
        Text,
        Other,
        Image,
        Menu,
    }

    public enum InfoKind
    {
        Name,
        Text,
        Measure,
        Options,
        NameText,
        MeasureText,
        Info,
        HowTo
    }

    public enum InfoOptions
    {
        ShowInInform,
        Support,
        ShowInSupported,
        TypeOfValue
    }

    [Flags]
    public enum InfoFileOptions
    {
        FileOption_Nothing = 0x00,
        FileOption_NoRecursive = 0x01,
        FileOption_CloseAll = 0x02,
        FileOption_Max = 0x04
    };

    [Flags]
    public enum Status
    {
        None = 0x00,
        Accepted = 0x01,
        Filled = 0x02,
        Updated = 0x04,
        Finalized = 0x08,
    }

    public partial class MediaInfo : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid
    {
        //Import of DLL functions. DO NOT USE until you know what you do (MediaInfo DLL do NOT use CoTaskMemAlloc to allocate memory)
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfo_New();
        [LibraryImport("MediaInfo.dll")]
        private static partial void MediaInfo_Delete(nint handle);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfo_Open(nint handle, [MarshalAs(UnmanagedType.LPWStr)] string FileName);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfoA_Open(nint handle, nint FileName);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfo_Open_Buffer_Init(nint handle, long File_Size, long File_Offset);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfoA_Open(nint handle, long File_Size, long File_Offset);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfo_Open_Buffer_Continue(nint handle, nint Buffer, nint Buffer_Size);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfoA_Open_Buffer_Continue(nint handle, long File_Size, byte[] Buffer, nint Buffer_Size);
        [LibraryImport("MediaInfo.dll")]
        private static partial long MediaInfo_Open_Buffer_Continue_GoTo_Get(nint handle);
        [LibraryImport("MediaInfo.dll")]
        private static partial long MediaInfoA_Open_Buffer_Continue_GoTo_Get(nint handle);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfo_Open_Buffer_Finalize(nint handle);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfoA_Open_Buffer_Finalize(nint handle);
        [LibraryImport("MediaInfo.dll")]
        private static partial void MediaInfo_Close(nint handle);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfo_Inform(nint handle, nint Reserved);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfoA_Inform(nint handle, nint Reserved);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfo_GetI(nint handle, nint StreamKind, nint StreamNumber, nint Parameter, nint KindOfInfo);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfoA_GetI(nint handle, nint StreamKind, nint StreamNumber, nint Parameter, nint KindOfInfo);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfo_Get(nint handle, nint StreamKind, nint StreamNumber, [MarshalAs(UnmanagedType.LPWStr)] string Parameter, nint KindOfInfo, nint KindOfSearch);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfoA_Get(nint handle, nint StreamKind, nint StreamNumber, nint Parameter, nint KindOfInfo, nint KindOfSearch);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfo_Option(nint handle, [MarshalAs(UnmanagedType.LPWStr)] string Option, [MarshalAs(UnmanagedType.LPWStr)] string Value);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfoA_Option(nint handle, nint Option, nint Value);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfo_State_Get(nint handle);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfo_Count_Get(nint handle, nint StreamKind, nint StreamNumber);

        //MediaInfo class
        public MediaInfo() : base(true)
        {
            try
            {
                handle = MediaInfo_New();
            }
            catch
            {
                handle = nint.Zero;
            }
            if (Environment.OSVersion.ToString().IndexOf("Windows") == -1)
                MustUseAnsi = true;
            else
                MustUseAnsi = false;
        }
        protected override bool ReleaseHandle()
        {
            try
            {
                if (IsInvalid)
                    return true;
                MediaInfo_Delete(handle);
                return true;
            }
            catch
            {
                return false;
            }
        }


        public int Open(string FileName)
        {
            if (handle == nint.Zero)
                return 0;
            if (MustUseAnsi)
            {
                nint FileName_Ptr = Marshal.StringToHGlobalAnsi(FileName);
                int ToReturn = (int)MediaInfoA_Open(handle, FileName_Ptr);
                Marshal.FreeHGlobal(FileName_Ptr);
                return ToReturn;
            }
            else
                return (int)MediaInfo_Open(handle, FileName);
        }
        public int Open_Buffer_Init(long File_Size, long File_Offset)
        {
            if (handle == nint.Zero) return 0; return (int)MediaInfo_Open_Buffer_Init(handle, File_Size, File_Offset);
        }
        public int Open_Buffer_Continue(nint Buffer, nint Buffer_Size)
        {
            if (handle == nint.Zero) return 0; return (int)MediaInfo_Open_Buffer_Continue(handle, Buffer, Buffer_Size);
        }
        public long Open_Buffer_Continue_GoTo_Get()
        {
            if (handle == nint.Zero) return 0; return (long)MediaInfo_Open_Buffer_Continue_GoTo_Get(handle);
        }
        public int Open_Buffer_Finalize()
        {
            if (handle == nint.Zero) return 0; return (int)MediaInfo_Open_Buffer_Finalize(handle);
        }
        public string? Inform()
        {
            if (handle == nint.Zero)
                return "Unable to load MediaInfo library";
            if (MustUseAnsi)
                return Marshal.PtrToStringAnsi(MediaInfoA_Inform(handle, nint.Zero));
            else
                return Marshal.PtrToStringUni(MediaInfo_Inform(handle, nint.Zero));
        }
        public string? Get(StreamKind StreamKind, int StreamNumber, string Parameter, InfoKind KindOfInfo, InfoKind KindOfSearch)
        {
            if (handle == nint.Zero)
                return "Unable to load MediaInfo library";
            if (MustUseAnsi)
            {
                nint Parameter_Ptr = Marshal.StringToHGlobalAnsi(Parameter);
                string? ToReturn = Marshal.PtrToStringAnsi(MediaInfoA_Get(handle, (nint)StreamKind, (nint)StreamNumber, Parameter_Ptr, (nint)KindOfInfo, (nint)KindOfSearch));
                Marshal.FreeHGlobal(Parameter_Ptr);
                return ToReturn;
            }
            else
                return Marshal.PtrToStringUni(MediaInfo_Get(handle, (nint)StreamKind, (nint)StreamNumber, Parameter, (nint)KindOfInfo, (nint)KindOfSearch));
        }
        public string? Get(StreamKind StreamKind, int StreamNumber, int Parameter, InfoKind KindOfInfo)
        {
            if (handle == nint.Zero)
                return "Unable to load MediaInfo library";
            if (MustUseAnsi)
                return Marshal.PtrToStringAnsi(MediaInfoA_GetI(handle, (nint)StreamKind, (nint)StreamNumber, (nint)Parameter, (nint)KindOfInfo));
            else
                return Marshal.PtrToStringUni(MediaInfo_GetI(handle, (nint)StreamKind, (nint)StreamNumber, (nint)Parameter, (nint)KindOfInfo));
        }
        public string? Option(string Option, string Value)
        {
            if (handle == nint.Zero)
                return "Unable to load MediaInfo library";
            if (MustUseAnsi)
            {
                nint Option_Ptr = Marshal.StringToHGlobalAnsi(Option);
                nint Value_Ptr = Marshal.StringToHGlobalAnsi(Value);
                string? ToReturn = Marshal.PtrToStringAnsi(MediaInfoA_Option(handle, Option_Ptr, Value_Ptr));
                Marshal.FreeHGlobal(Option_Ptr);
                Marshal.FreeHGlobal(Value_Ptr);
                return ToReturn;
            }
            else
                return Marshal.PtrToStringUni(MediaInfo_Option(handle, Option, Value));
        }
        public int State_Get() { if (handle == nint.Zero) return 0; return (int)MediaInfo_State_Get(handle); }
        public int Count_Get(StreamKind StreamKind, int StreamNumber) { if (handle == nint.Zero) return 0; return (int)MediaInfo_Count_Get(handle, (nint)StreamKind, (nint)StreamNumber); }

        private bool MustUseAnsi;

        //Default values, if you know how to set default values in C#, say me
        public string? Get(StreamKind StreamKind, int StreamNumber, string Parameter, InfoKind KindOfInfo) { return Get(StreamKind, StreamNumber, Parameter, KindOfInfo, InfoKind.Name); }
        public string? Get(StreamKind StreamKind, int StreamNumber, string Parameter) { return Get(StreamKind, StreamNumber, Parameter, InfoKind.Text, InfoKind.Name); }
        public string? Get(StreamKind StreamKind, int StreamNumber, int Parameter) { return Get(StreamKind, StreamNumber, Parameter, InfoKind.Text); }
        public string? Option(string Option_) { return Option(Option_, ""); }
        public int Count_Get(StreamKind StreamKind) { return Count_Get(StreamKind, -1); }
    }




    public partial class MediaInfoList : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid
    {
        //Import of DLL functions. DO NOT USE until you know what you do (MediaInfo DLL do NOT use CoTaskMemAlloc to allocate memory)
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfoList_New();
        [LibraryImport("MediaInfo.dll")]
        private static partial void MediaInfoList_Delete(nint handle);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfoList_Open(nint handle, [MarshalAs(UnmanagedType.LPWStr)] string FileName, nint Options);
        [LibraryImport("MediaInfo.dll")]
        private static partial void MediaInfoList_Close(nint handle, nint FilePos);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfoList_Inform(nint handle, nint FilePos, nint Reserved);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfoList_GetI(nint handle, nint FilePos, nint StreamKind, nint StreamNumber, nint Parameter, nint KindOfInfo);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfoList_Get(nint handle, nint FilePos, nint StreamKind, nint StreamNumber, [MarshalAs(UnmanagedType.LPWStr)] string Parameter, nint KindOfInfo, nint KindOfSearch);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfoList_Option(nint handle, [MarshalAs(UnmanagedType.LPWStr)] string Option, [MarshalAs(UnmanagedType.LPWStr)] string Value);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfoList_State_Get(nint handle);
        [LibraryImport("MediaInfo.dll")]
        private static partial nint MediaInfoList_Count_Get(nint handle, nint FilePos, nint StreamKind, nint StreamNumber);

        //MediaInfo class
        public MediaInfoList() : base(true) { handle = MediaInfoList_New(); }
        //~MediaInfoList() { MediaInfoList_Delete(handle); }
        protected override bool ReleaseHandle()
        {
            try
            {
                if (IsInvalid)
                    return true;
                MediaInfoList_Delete(handle);
                return true;
            }
            catch
            {
                return false;
            }
        }
        public int Open(string FileName, InfoFileOptions Options) { return (int)MediaInfoList_Open(handle, FileName, (nint)Options); }
        public void Close(int FilePos = -1) { MediaInfoList_Close(handle, (nint)FilePos); }
        public string? Inform(int FilePos) { return Marshal.PtrToStringUni(MediaInfoList_Inform(handle, (nint)FilePos, nint.Zero)); }

        public string? Get(int FilePos, StreamKind StreamKind, int StreamNumber, string Parameter, InfoKind KindOfInfo, InfoKind KindOfSearch) { return Marshal.PtrToStringUni(MediaInfoList_Get(handle, (nint)FilePos, (nint)StreamKind, (nint)StreamNumber, Parameter, (nint)KindOfInfo, (nint)KindOfSearch)); }
        public string? Get(int FilePos, StreamKind StreamKind, int StreamNumber, int Parameter, InfoKind KindOfInfo) { return Marshal.PtrToStringUni(MediaInfoList_GetI(handle, (nint)FilePos, (nint)StreamKind, (nint)StreamNumber, (nint)Parameter, (nint)KindOfInfo)); }
        public string? Option(string Option, string Value) { return Marshal.PtrToStringUni(MediaInfoList_Option(handle, Option, Value)); }
        public int State_Get() { return (int)MediaInfoList_State_Get(handle); }
        public int Count_Get(int FilePos, StreamKind StreamKind, int StreamNumber) { return (int)MediaInfoList_Count_Get(handle, (nint)FilePos, (nint)StreamKind, (nint)StreamNumber); }


        //Default values, if you know how to set default values in C#, say me
        public void Open(string FileName) { Open(FileName, 0); }
        public string? Get(int FilePos, StreamKind StreamKind, int StreamNumber, string Parameter, InfoKind KindOfInfo) { return Get(FilePos, StreamKind, StreamNumber, Parameter, KindOfInfo, InfoKind.Name); }
        public string? Get(int FilePos, StreamKind StreamKind, int StreamNumber, string Parameter) { return Get(FilePos, StreamKind, StreamNumber, Parameter, InfoKind.Text, InfoKind.Name); }
        public string? Get(int FilePos, StreamKind StreamKind, int StreamNumber, int Parameter) { return Get(FilePos, StreamKind, StreamNumber, Parameter, InfoKind.Text); }
        public string? Option(string Option_) { return Option(Option_, ""); }
        public int Count_Get(int FilePos, StreamKind StreamKind) { return Count_Get(FilePos, StreamKind, -1); }
    }


} //NameSpace
